/**
 * Copyright (c) 2011-2015 1lifes.com
 * HSJ java-handlersocket
 * Id: DefaultHSJManager.java
 */
package com.elifes.hsj.impl;

import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import org.apache.log4j.Logger;

import com.elifes.hsj.HSJManager;
import com.elifes.hsj.IDBLookupStrategy;
import com.elifes.hsj.client.HSJClient;
import com.elifes.hsj.exception.HSJException;
import com.elifes.hsj.model.CompareOperator;
import com.elifes.hsj.model.Filter;
import com.elifes.hsj.model.INFilter;
import com.elifes.hsj.model.Modify;
import com.elifes.hsj.model.TableConfig;
import com.elifes.hsj.packet.IPacket;
import com.elifes.hsj.packet.PacketFactory;
import com.elifes.hsj.util.Constants;

/**
 * 描述：hs对外提供服务的管理类
 * @author yangqiang
 * @createtime 2011-11-12下午12:40:13
 *
 */
public class DefaultHSJManager implements HSJManager {
	private static final Logger logger = Logger.getLogger(DefaultHSJManager.class);
	
	private static DefaultHSJManager self = new DefaultHSJManager();
	
	private Executor executor = Executors.newFixedThreadPool(80);
	
	private ConcurrentMap<TableConfig, FutureTask<String>> indexIdMap = new ConcurrentHashMap<TableConfig, FutureTask<String>>();
	//ThreadLocal<OpenIndexContext> ctx;

	//private IDBLookupStrategy dbLookupStrategy;
	private String encoding = Constants.DEFAULT_ENCODING;
	private TableConfig tableConfig;
	
//	static{
//		init();
//	}
	
	public static DefaultHSJManager getInstance(){
		return self;
	}
	
	public String init(IDBLookupStrategy dbLookupStrategy, Map<String, Object> lookupKeyMap) throws HSJException {
		return init(dbLookupStrategy, lookupKeyMap, false);
	}

	public String init(IDBLookupStrategy dbLookupStrategy, Map<String, Object> lookupKeyMap, final boolean isReOpen) throws HSJException {
		tableConfig = dbLookupStrategy.lookup(lookupKeyMap);
		String indexId = null;
 
		try {
			FutureTask<String> future = indexIdMap.get(tableConfig);
			if(future == null || future.get() == null || isReOpen){
				future = new FutureTask<String>(new Callable<String>() {
	
					public String call() throws Exception {
						return openIndex(tableConfig);
					}
				});
				
				future = indexIdMap.putIfAbsent(tableConfig, future);
				if(future == null){
					future = indexIdMap.get(tableConfig);
					future.run();
				}
				if(isReOpen){
					return openIndex(tableConfig, future.get());
				}
			}
			indexId = future.get();
		} catch (InterruptedException e) {
			throw new HSJException("init error!", e);
		} catch (ExecutionException e) {
			throw new HSJException("init error!", e);
		}
		
//		if(!indexIdMap.containsKey(tableConfig)){
//			indexId = openIndex(tableConfig);
//			indexIdMap.putIfAbsent(tableConfig, indexId);
//		}
		return indexId;
	}

	private String openIndex(TableConfig tableConfig) throws HSJException {
		return openIndex(null, 
				tableConfig.getDbConfig().getDbName(),
				tableConfig.getTblName(), tableConfig.getIndexName(),
				tableConfig.getColumnNames(), tableConfig.getFilterColumnNames());
	}
	
	private String openIndex(TableConfig tableConfig, String indexId) throws HSJException {
		return openIndex(indexId,
				tableConfig.getDbConfig().getDbName(),
				tableConfig.getTblName(), tableConfig.getIndexName(),
				tableConfig.getColumnNames(), tableConfig.getFilterColumnNames());
	}

	private String openIndex(String indexId, String dbName, String tblName, String indexName,
			List<String> columnNames, List<String> filterColumnNames) throws HSJException {
		return getClient().requsetOpenIndex(indexId, dbName, tblName, indexName, columnNames, filterColumnNames);
	}

	/* (non-Javadoc)
	 * @see com.elifes.hsj.HSJManager#insert(java.lang.String, java.util.List)
	 */
	public boolean insert(String indexId, List<String> values) throws HSJException {
		IPacket insertPacket = PacketFactory.getInstance().createInsertPacket(indexId, values);
		
		return getClient().requsetInsert(insertPacket);
	}

	/* (non-Javadoc)
	 * @see com.elifes.hsj.HSJManager#find(java.lang.String, com.elifes.hsj.model.CompareOperator, java.lang.String[], int, int, java.lang.String[])
	 */
	public Object find(String indexId, CompareOperator operator,
			List<String> filterValues, int limit, int offset,
			INFilter in, List<Filter> filters, Class doClass, List<String> properties) throws HSJException {
		IPacket findPacket = PacketFactory.getInstance().createFindPacket(
				indexId, operator, filterValues, limit, offset, in, filters, doClass, properties);
		
		return getClient().requsetFind(findPacket);
	}

	public Object modify(String indexId, CompareOperator operator,
			List<String> filterValues, int limit, int offset, INFilter in,
			List<Filter> filters, Class doClass, List<String> properties,
			Modify mod) throws HSJException {
		IPacket modifyPacket = PacketFactory.getInstance().createModifyPacket(
				indexId, operator, filterValues, limit, offset, in, filters, doClass, properties, mod);
		
		return getClient().requsetModify(modifyPacket);
	}

	public Future<Boolean> asynInsert(String indexId, List<String> values)
			throws HSJException {
		IPacket insertPacket = PacketFactory.getInstance().createInsertPacket(indexId, values);
		
		return getClient().asynRequsetInsert(insertPacket);
	}

	public Future<Object> asynFind(String indexId, CompareOperator operator,
			List<String> filterValues, int limit, int offset, INFilter in,
			List<Filter> filters, Class doClass, List<String> properties) throws HSJException {
		IPacket findPacket = PacketFactory.getInstance().createFindPacket(
				indexId, operator, filterValues, limit, offset, in, filters, doClass, properties);
		
		return (Future<Object>) getClient().asynRequsetFind(findPacket);
	}

	public Future<Object> asynModify(String indexId, CompareOperator operator,
			List<String> filterValues, int limit, int offset, INFilter in,
			List<Filter> filters, Class doClass, List<String> properties,
			Modify mod) throws HSJException {
		IPacket modifyPacket = PacketFactory.getInstance().createModifyPacket(
				indexId, operator, filterValues, limit, offset, in, filters, doClass, properties, mod);
		
		return getClient().asynRequsetModify(modifyPacket);
	}

	public HSJClient getClient(){
		HSJClient hsjClient = HSJClient.getInstance();
		return hsjClient;
	}

//	public void setDbLookupStrategy(IDBLookupStrategy dbLookupStrategy) {
//		this.dbLookupStrategy = dbLookupStrategy;
//	}


}
